using System;
using System.Collections.Generic;
using System.Text;
using Util;
using System.Text.RegularExpressions;

namespace Crm.Domain
{
    /// <summary>
    /// Business key for a <see cref="Customer"/> instance.
    /// </summary>
    /// <remarks>
    /// This is a value object.
    /// </remarks>
    public sealed class CustomerIdentifier
    {
        #region Constants

        private const string ValidationRegularExpression = "[A-Z|a-z]{3}[0-9]{1}";

        #endregion

        # region Static Fields

        private static Regex _regex = new Regex(ValidationRegularExpression);

        # endregion

        #region Fields

        private string _identifier;

        #endregion

        #region Constructor

        /// <summary>
        /// Creates an instance of this class.
        /// </summary>
        /// <param name="identifier">The customer identifier string.</param>
        /// <exception cref="ArgumentNullException"><paramref name="identifier"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException"><paramref name="identifier"/> is not a suitable customer identifier.</exception>
        public CustomerIdentifier(string identifier)
        {
            #region Preconditions

            ThrowIfIdentifierInvalid(identifier);

            #endregion

            _identifier = identifier;
        }

        #endregion

        #region Overrides

        public override string ToString()
        {
            return _identifier;
        }

        /// <summary>
        /// Determines whether the specified object is equal to this object.
        /// </summary>
        /// <param name="obj">The Object to compare with the current object.</param>
        /// <returns><c>true</c> if the specified Object is equal to the current Object; otherwise, <c>false</c>.</returns>
        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }

            if (Object.ReferenceEquals(this, obj))
            {
                return true;
            }

            if (this.GetType() != obj.GetType())
            {
                return false;
            }

            CustomerIdentifier toCompareTo = (CustomerIdentifier)obj;

            return _identifier == toCompareTo._identifier;
        }

        /// <summary>
        /// Gets a hash code for the current object.
        /// </summary>
        /// <returns>A hash code for the current object.</returns>
        public override int GetHashCode()
        {
            return _identifier.GetHashCode();
        }

        #endregion

        #region Support Methods
        
        /// <summary>
        /// Throws the appropriate exception if <paramref name="identifier"/> is <c>null</c>.
        /// </summary>
        /// <exception cref="ArgumentNullException"><paramref name="identifier"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException"><paramref name="identifier"/> is not a suitable customer identifier.</exception>
        private void ThrowIfIdentifierInvalid(string identifier)
        {
            ArgumentValidation.ThrowIfNull(identifier, "identifier");

            if (MatchesRegularExpression(identifier) == false)
            {
                throw new ArgumentException("The provided value is not a valid customer identifier", "identifier");
            }
        }

        private bool MatchesRegularExpression(string identifier)
        {
            return _regex.IsMatch(identifier);
        }

        #endregion
    }
}
